#ifndef UNI_OPS_OUT_CLASS_H
#define UNI_OPS_OUT_CLASS_H

template <class T, class OP>
struct uni_ops_deducer
{
	struct sub_fail {};

	typedef typename as_expression<T>::expr_T expr_T;
	typedef expression_unary<expr_T, OP> expr_result_T;
		
	inline static expression<expr_result_T> dispatch( const T& v )
	{		
		return expression<expr_result_T>( 
			expr_result_T( as_expression<T>::create(v) )
		);
	}

	static sub_fail	dispatch( ... ); //! SFINAE
};

#define DECLARE_ARRAY_EXPR_UNI_OPS_OUT_CLASS( OP, OP_CLASS ) 			\
																		\
/* OP array<T,N> */														\
template <typename T, unsigned int DIM>									\
auto operator OP( const array<T, DIM>& v ) ->							\
decltype( uni_ops_deducer<array<T, DIM>, OP_CLASS>::dispatch( v ) )		\
{  return uni_ops_deducer<array<T, DIM>, OP_CLASS>::dispatch( v ); }	\
																		\
/* OP expression<expr_T> */												\
template <typename expr_T>												\
auto operator OP( const expression<expr_T>& v ) ->						\
decltype( uni_ops_deducer<expression<expr_T>, OP_CLASS>::dispatch( v ) )\
{  return uni_ops_deducer<expression<expr_T>, OP_CLASS>::dispatch( v ); }\

																																																		
DECLARE_ARRAY_EXPR_UNI_OPS_OUT_CLASS( -, unary_ops::minus_op )
DECLARE_ARRAY_EXPR_UNI_OPS_OUT_CLASS( +, unary_ops::plus_op )
DECLARE_ARRAY_EXPR_UNI_OPS_OUT_CLASS( ~, unary_ops::bitwise_not_op )
DECLARE_ARRAY_EXPR_UNI_OPS_OUT_CLASS( !, unary_ops::logical_not_op )
	
#endif //!< UNI_OPS_OUT_CLASS_H